/***************************************************************************
 *   Copyright (C) 2007 by vasaka,,,   *
 *   vasaka@gmail.com   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 3 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#ifndef CLUSTERPOINT_H
#define CLUSTERPOINT_H

const unsigned short EXTRACT_COLOR = 0;

#include <list>
#include <stdio.h>
#include <vector>

using namespace std;


//this is Cluster image class, actually I also need bitmap image class 
//and should think if I also need abstract image, cause I'll need fractal Image also 
//this one should contain only marking information, not colours of the pixels thamselfs?
class CImage
{
  public:
    CImage ( int* img_,int Width_ , int Height_):img_m(img_),Points_m(Width_m*Height_m),Height_m(Height_),Width_m(Width_),AdjacentThrehold_m(20),ExtractThrehold_m(256) 
      {printf("CImage constructor sizeof ClasterPoint=%i\n",sizeof(ClasterPoint));
      IfAdjacentPointer = &CImage::IfAdjacentDist;
      }
    CImage ():img_m(0),Points_m(0),Height_m(0),Width_m(0) {printf("CImage constructor w/o params\n sizeof ClasterPoint=%i\n",sizeof(ClasterPoint));}
    ~CImage(){};
 
    void SetPointBitmap ( int x, int y, int color );//x,y - coordinates, color is int color
    int GetPointBitmap ( int x, int y);
    //everething about marks
    enum MarkVisited
    {
    	Visited=1,
    	NotVisited=0
    };
    enum MarkDeleted
    {
    	Deleted=1,
    	NotDeleted=0
    };    
    enum MarkGeneral
    {
    	Disabled=0,
    	Enabled=1
    };        
    enum MarkTrue
    {
    	True=1,
    }; 
    
    //switch all tjis shit to templates, keep header clear
    void SetMark (int x, int y,MarkVisited Mark_) {Points_m[x+Width_m*y].mark_visited_m=Mark_;}
    bool IfMarked (int x, int y,MarkVisited Mark_) {return Points_m[x+Width_m*y].mark_visited_m==Mark_;}
    MarkVisited SwitchMark (int x, int y,MarkVisited Mark_) {return MarkVisited(Points_m[x+Width_m*y].mark_visited_m=1-Points_m[x+Width_m*y].mark_visited_m);} 
    
    void SetMark (int x, int y,MarkDeleted Mark_) {Points_m[x+Width_m*y].mark_delete_m=Mark_;}
    bool IfMarked (int x, int y,MarkDeleted Mark_) {return Points_m[x+Width_m*y].mark_delete_m==Mark_;}
    MarkDeleted SwitchMark (int x, int y,MarkDeleted Mark_) {return MarkDeleted(Points_m[x+Width_m*y].mark_delete_m=1-Points_m[x+Width_m*y].mark_delete_m);}
    
    void SetMark (int x, int y,MarkGeneral Mark_) {Points_m[x+Width_m*y].mark_general_m=Mark_;}
    bool IfMarked (int x, int y,MarkGeneral Mark_) {return Points_m[x+Width_m*y].mark_general_m==Mark_;}
    MarkGeneral SwitchMark (int x, int y,MarkGeneral Mark_) {return MarkGeneral(Points_m[x+Width_m*y].mark_general_m=1-Points_m[x+Width_m*y].mark_general_m);}

    void SetMark (int x, int y,MarkTrue Mark_) {}
    bool IfMarked (int x, int y,MarkTrue Mark_) {return true;}
    void SwitchMark (int x, int y,MarkTrue Mark_) {}    
    
    void ClearMarks(int x, int y)
    {Points_m[x+Width_m*y].mark_visited_m=0;Points_m[x+Width_m*y].mark_general_m=0;Points_m[x+Width_m*y].mark_delete_m=0;}
   
    static MarkVisited InvertMark(MarkVisited Mark_) {return Mark_==Visited ? NotVisited:Visited;}
    static MarkDeleted InvertMark(MarkDeleted Mark_) {return Mark_==Deleted ? NotDeleted:Deleted;}
    static MarkGeneral InvertMark(MarkGeneral Mark_) {return Mark_==Disabled ? Enabled:Disabled;}
    static MarkTrue InvertMark(MarkTrue Mark_) {return True;}    
    
    void Resize ( int* img_, int x,int y );
    int GetHeight() {return Height_m;};
    int GetWidth() {return Width_m;};
    
    bool (CImage::*IfAdjacentPointer)(int x1, int y1,int x2, int y2); 
    bool IfAdjacentDist(int x1, int y1,int x2, int y2) 
    {return abs((img_m[x1+Width_m*y1]&0x0000ff)-(img_m[x2+Width_m*y2]&0x0000ff))<AdjacentThrehold_m;} 
    bool IfAdjacentTrue(int x1, int y1,int x2, int y2){return true;} 
    bool validCoordinates(int x, int y) {return (x>=0)&(y>=0)&(x<Width_m)&(y<Height_m);}
    bool ShouldExtract(int x, int y){return abs(img_m[x+Width_m*y]&0x0000ff)<ExtractThrehold_m;}
    void SetOutput(int* img_){imgout_m = img_;}//this is ugly, think about clear output design
    void SetAdjacentThrehold_m(int thr_){AdjacentThrehold_m=thr_;}
    
    struct ClasterPoint    
    {
      ClasterPoint():mark_general_m(0),mark_visited_m(0),mark_delete_m(0){}
      unsigned char mark_general_m:1;//this is temporary mark, only for use locally
      unsigned char mark_visited_m:1;
      unsigned char mark_delete_m:1;
    }; 
  protected:
	int* img_m;//img is created externally
	int* imgout_m;//this is ugly, think about clear output design
    vector< ClasterPoint > Points_m;
    int Height_m;
    int Width_m;
    int AdjacentThrehold_m;
    int ExtractThrehold_m;
};

class Ctraveller
{
  protected:	
    struct Shift
    {
      short x,y;
      Shift ( int xx,int yy ) :x ( xx ),y ( yy ) {}
    };
    
  public:
    Ctraveller ( short x, short y, CImage *im );
    template<typename MARK> list< Ctraveller > GetNeighbours(MARK Mark_,bool (CImage::*AdjFunc_)(int x1, int y1,int x2, int y2), vector< Shift > Neighbours_) const;
    template<typename MARK> list< Ctraveller > Ctraveller::GetNeighbours(MARK Mark_,bool (CImage::*AdjFunc_)(int, int,int, int), vector< Shift >::iterator begin_, vector< Shift >::iterator end_) const;
    
    short GetX() {return x_m;}
    short GetY() {return y_m;}
    
    //switch all tjis shit to templates, keep header clear
    void SetMark (CImage::MarkVisited Mark_) const {Parent->SetMark(x_m, y_m,Mark_);}
    unsigned char IfMarked (CImage::MarkVisited Mark_) const {return Parent->IfMarked(x_m, y_m,Mark_);}
    CImage::MarkVisited SwitchMark (CImage::MarkVisited Mark_) const {return Parent->SwitchMark(x_m, y_m,Mark_);}
    
    void SetMark (CImage::MarkGeneral Mark_) const {Parent->SetMark(x_m, y_m,Mark_);}
    unsigned char IfMarked (CImage::MarkGeneral Mark_) const {return Parent->IfMarked(x_m, y_m,Mark_);}
    CImage::MarkGeneral SwitchMark (CImage::MarkGeneral Mark_) const {return Parent->SwitchMark(x_m, y_m,Mark_);}    
    
    void SetMark (CImage::MarkDeleted Mark_) const {Parent->SetMark(x_m, y_m,Mark_);}
    unsigned char IfMarked (CImage::MarkDeleted Mark_) const {return Parent->IfMarked(x_m, y_m,Mark_);}
    CImage::MarkDeleted SwitchMark (CImage::MarkDeleted Mark_) const {return Parent->SwitchMark(x_m, y_m,Mark_);}  
    
    void SetColorBitmap(int color) {return Parent->SetPointBitmap(x_m,y_m,color);}
    int GetColorBitmap() const {return Parent->GetPointBitmap(x_m,y_m);}
    
    static vector< Shift > Neighbours_sm;
    static vector< Shift > Clique2_sm;
    static vector< Shift > Clique3_sm;
    static vector< Shift > Clique4_sm;
  protected:
	CImage *Parent;
    short x_m,y_m;    
};

template<class MARK> unsigned int MarkClaster ( const Ctraveller &StartPoint,MARK Mark_);
unsigned int PaintClasterOnBitmap ( const Ctraveller &StartPoint,int m,CImage::MarkVisited Mark_);
unsigned int FilterClasterOnBitmap ( const Ctraveller &StartPoint,CImage::MarkVisited Mark_);
unsigned int CopyClasterOnBitmap ( const Ctraveller &StartPoint,CImage::MarkVisited Mark_);
unsigned int PaintGibbsMeasureOnBitmap ( const Ctraveller &StartPoint,CImage::MarkVisited Mark_);

#endif
